#include "w55mh32_adc.h"
#include "w55mh32_gpio.h"
#include "w55mh32_rcc.h"

/**
 * @brief Initialize PWM module (TIM5 timer + PA0 pin)
 * @note Configuration steps:
 * 1. Enable TIM5 and GPIOA clock
 * 2. Configure PA0 as alternate function push-pull output (PWM signal output)
 * 3. Initialize TIM5: up counting, period 100 (0-99), prescaler 2160 (generate
 * 100kHz clock)
 * 4. Configure TIM5 channel 1 as PWM1 mode, initial duty cycle 0
 * 5. Enable TIM5 timer
 */
void pwm_init(void) {
  // Enable TIM5 and GPIOA clock
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

  // Configure PA0 as alternate function push-pull output (PWM output)
  GPIO_InitTypeDef gpio_init_structure;
  gpio_init_structure.GPIO_Mode = GPIO_Mode_AF_PP;
  gpio_init_structure.GPIO_Pin = GPIO_Pin_0;
  gpio_init_structure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &gpio_init_structure);

  // Configure TIM5 internal clock
  TIM_InternalClockConfig(TIM5);

  // Initialize TIM5 time base parameters
  TIM_TimeBaseInitTypeDef tim_time_base_init_structure;
  tim_time_base_init_structure.TIM_ClockDivision = TIM_CKD_DIV1;
  tim_time_base_init_structure.TIM_CounterMode = TIM_CounterMode_Up;
  tim_time_base_init_structure.TIM_Period = 100 - 1; // Period 100 (0-99)
  tim_time_base_init_structure.TIM_Prescaler =
      2160 - 1; // Prescaler 2160 (216MHz/2160=100kHz)
  tim_time_base_init_structure.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInit(TIM5, &tim_time_base_init_structure);

  // Configure TIM5 channel 1 as PWM mode
  TIM_OCInitTypeDef tim_oc_init_structure;
  TIM_OCStructInit(&tim_oc_init_structure); // Initialize default parameters
  tim_oc_init_structure.TIM_OCMode =
      TIM_OCMode_PWM1; // PWM1 mode (counter<compare value outputs valid)
  tim_oc_init_structure.TIM_OCPolarity =
      TIM_OCPolarity_High; // Valid level is high
  tim_oc_init_structure.TIM_OutputState =
      TIM_OutputState_Enable;          // Enable output
  tim_oc_init_structure.TIM_Pulse = 0; // Initial duty cycle 0
  TIM_OC1Init(TIM5, &tim_oc_init_structure);

  // Enable TIM5 timer
  TIM_Cmd(TIM5, ENABLE);
}

/**
 * @brief Set TIM5 channel 1 PWM duty cycle
 * @param compare: Duty cycle value (0-100, corresponding to 0%-100%)
 * @note Directly modify the compare register value to update PWM output in real
 * time
 */
void pwm_set_compare1(uint16_t compare) { TIM_SetCompare1(TIM5, compare); }
